package com.haust.service.impl;

import com.haust.config.WeChatConfig;
import com.haust.entity.User;
import com.haust.entity.Video;
import com.haust.entity.VideoOrder;
import com.haust.mapper.UserMapper;
import com.haust.mapper.VideoMapper;
import com.haust.mapper.VideoOrderMapper;
import com.haust.pojo.VideoOrderPojo;
import com.haust.service.VideoOrderService;
import com.haust.util.CommonUtils;
import com.haust.util.HTTPUtils;
import com.haust.util.WXPayUtil;
import com.haust.util.wxutils.WXPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Auther: csp1999
 * @Date: 2020/08/29/15:38
 * @Description: 视频订单 Service 实现类
 */
@Service
public class VideoOrderServiceImpl implements VideoOrderService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private Logger dataLogger = LoggerFactory.getLogger("dataLogger");

    @Autowired
    private WeChatConfig weChatConfig;

    @Autowired
    private VideoMapper videoMapper;

    @Autowired
    private VideoOrderMapper videoOrderMapper;

    @Autowired
    private UserMapper userMapper;

    /*
     * @方法描述: 生成、保存订单信息并调用统一下单,
     * @参数集合: [videoOrderPojo]
     * @返回类型: com.haust.entity.VideoOrder
     * @作者名称: csp1999
     * @日期时间: 2020/8/29 17:25
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED)// Propagation 事务传播类型 REQUIRED:支持当前事务，如果不存在则创建一个新事务
    public String save(VideoOrderPojo videoOrderPojo) throws Exception {

        dataLogger.info("module=video_order`api=save`user_id={}`video_id={}",videoOrderPojo.getUserId(),videoOrderPojo.getVideoId());

        // 根据id 查找video信息
        Video video = videoMapper.findVideoById(videoOrderPojo.getVideoId());

        // 查找 用户信息
        User user = userMapper.findByUserId(videoOrderPojo.getUserId());

        // 构造订单对象
        VideoOrder videoOrder = new VideoOrder();
        videoOrder.setTotalFee(video.getPrice());
        videoOrder.setVideoImg(video.getCoverImg());
        videoOrder.setVideoTitle(video.getTitle());
        videoOrder.setCreateTime(new Date());
        videoOrder.setVideoId(video.getId());
        videoOrder.setState(0);
        videoOrder.setUserId(user.getId());
        videoOrder.setHeadImg(user.getHeadImg());
        videoOrder.setNickname(user.getName());
        videoOrder.setDel(0);
        videoOrder.setIp(videoOrderPojo.getIp());
        videoOrder.setOutTradeNo(CommonUtils.getUUID());
        videoOrderMapper.insertVideoOrder(videoOrder);

        // 统一下单，获取codeurl
        String codeUrl = unifiedOrder(videoOrder);

        return codeUrl;
    }

    /*
    * @方法描述: 根据流水号查找订单
    * @参数集合: [outTradeNo]
    * @返回类型: com.haust.entity.VideoOrder
    * @作者名称: csp1999
    * @日期时间: 2020/8/29 22:29
    */
    @Override
    public VideoOrder findByVideoOrderOutTradeNo(String outTradeNo) {

        return videoOrderMapper.findVideoOrderByOutTradeNo(outTradeNo);
    }

    /*
    * @方法描述: 根据流水号更新订单
    * @参数集合: [videoOrder]
    * @返回类型: int
    * @作者名称: csp1999
    * @日期时间: 2020/8/29 22:28
    */
    @Override
    public int updateVideoOderByOutTradeNo(VideoOrder videoOrder) {

        return videoOrderMapper.updateVideoOrderByOutTradeNo(videoOrder);
    }

    /*
     * @方法描述: 统一下单方法请求微信统一下单接口,并最终获取微信支付二维码图片的url
     * @参数集合: [videoOrder]
     * @返回类型: java.lang.String
     * @作者名称: csp1999
     * @日期时间: 2020/8/29 16:33
     */
    public String unifiedOrder(VideoOrder videoOrder) throws Exception {
        //int i = 1/0;   //模拟异常,检测事务是否成功

        WXPay wxPay = new WXPay();

        // 使用 map 封装 订单参数以及微信支付相关参数
        HashMap<String, String> data = new HashMap<>();
        // 没必要再做有序map了，因为WXPayUtils.generateSignature(data,xx) 中已经有对map进行排序的代码了
        // SortedMap<String, String> data = new TreeMap<>();

        data.put("appid", weChatConfig.getAppid());// 公众账号ID: 微信支付分配的公众账号ID（企业号corpid即为此appId）
        data.put("mch_id", weChatConfig.getMchId());// 商户号: 微信支付分配的商户号
        data.put("nonce_str", CommonUtils.getUUID());// 随机字符串: 自定义参数，可以为终端设备号(门店号或收银设备ID)，PC网页或公众号内支付可以传"WEB"
        data.put("body", videoOrder.getVideoTitle());// 商品描述
        data.put("out_trade_no", videoOrder.getOutTradeNo());// 商户订单号: 要求32个字符内，只能是数字、大小写字母_-|* 且在同一个商户号下唯一。
        data.put("total_fee", videoOrder.getTotalFee().toString());// 标价金额: 单位为分
        data.put("spbill_create_ip", videoOrder.getIp());// 下单用户的客户端IP
        data.put("notify_url", weChatConfig.getPayCallbackUrl());// 通知地址: 异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。
        data.put("trade_type", "NATIVE");// 交易类型: 此处指定为扫码支付

        // 生成 sign 签名
        String sign = WXPayUtil.generateSignature(data, weChatConfig.getKey());
        data.put("sign", sign);// 签名: 微信返回的签名值

        System.out.println("---------------------- xml 数据如下：----------------------");
        // map 转 xml
        String payXmlData = WXPayUtil.mapToXml(data);
        System.out.println(payXmlData);

        // 统一下单,发送POST请求微信后台统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder 获取返回xml格式的字符串 orderStr
        String orderStr = HTTPUtils.doPost(WeChatConfig.getUnifiedOrderUrl(), payXmlData, 4000);
        System.out.println("---------------------- 请求统一下单接口返回的 orderStr 数据如下：----------------------");
        System.out.println(orderStr);

        if (null == orderStr) {
            return null;
        }

        // 将统一下单接口返回的xml格式的字符串 orderStr 转成 map
        Map<String, String> unifiedOrderMap = WXPayUtil.xmlToMap(orderStr);
        System.out.println("---------------------- 转换成 map 的 orderStr 数据如下：----------------------");
        // 这样做的目的是解决打印出的对象中文乱码问题，无法阅读错误提示信息
        String string = new String(unifiedOrderMap.toString().getBytes("ISO-8859-1"), "UTF-8");
        System.out.println(string);

        if (unifiedOrderMap != null) {
            System.out.println("支付二维码url:" + unifiedOrderMap.get("code_url"));
            return unifiedOrderMap.get("code_url");// 获取统一下单接口返回的 code_url(支付二维码图片的url) 数据
        }

        // 否则返回null
        return null;
    }
}
